#include "syntax_error.h"
#include "cpp-gen/FormalParser.h"
#include "syntax_error_formatter.hpp"
#include "utils.h"

namespace cyclone::parser
{
    using antlr4::FailedPredicateException;
    using antlr4::InputMismatchException;
    using antlr4::NoViableAltException;

    SyntaxError::SyntaxError(Parser *recognizer) : SyntaxError(recognizer, "") {}
    SyntaxError::SyntaxError(const RecognitionException &ex) : SyntaxError(static_cast<antlr4::Parser *>(ex.getRecognizer()), Utils::getNonSemanticErrorInfoTip()) {}
    SyntaxError::SyntaxError(Parser *recognizer, const std::string &msg) : RecognitionException(msg, recognizer,
                                                                                                recognizer->getInputStream(), recognizer->getContext(), recognizer->getCurrentToken()),
                                                                           message(msg)
    {
        if (recognizer->getTokenStream() && recognizer->getTokenStream()->size())
        {
            const auto lastToken = recognizer->getTokenStream()->get(recognizer->getTokenStream()->size() - 1);
            location.line = lastToken->getLine();
            location.column = lastToken->getCharPositionInLine();
        }
    }

    SyntaxError::SyntaxError(Parser *recognizer, const std::string &msg, const SourceCodeLocation &loc) : SyntaxError(recognizer, msg)
    {
        location = loc;
    }
    SyntaxError::~SyntaxError()
    {
    }

    void SyntaxError::handleNonSemanticError(Parser *parserPtr)
    {
#ifdef CYCLONE_PARSER_DEBUG
        auto showRuleInvocationStack = [&]()
        {
            const auto text = parserPtr->getCurrentToken()->getText();
            const auto involvingStack = parserPtr->getRuleInvocationStack();
            std::cout << "Token: " << text << std::endl
                      << "involvingStack : ";
            for (const auto name : involvingStack)
                std::cout << name << " ";
            std::cout << std::endl;
        };
        assert(dynamic_cast<CycloneParserBase *>(parserPtr));
        showRuleInvocationStack();
#endif
        try
        {
            throw;
        }
        catch (FailedPredicateException &ex)
        {
            // throw SyntaxError(parserPtr, "failed predicate: " + ex.getPredicate() + "?");
            // Unify error message
            throw SyntaxError(parserPtr, Utils::getNonSemanticErrorInfoTip());
        }
        catch (InputMismatchException &ex)
        {
            throw SyntaxError(ex);
        }
        catch (NoViableAltException &ex)
        {
            throw SyntaxError(ex);
        }
        catch (RecognitionException &ex)
        {
            throw SyntaxError(ex);
        }
        // NOTE shall not come here
        catch (...)
        {
            std::rethrow_exception(std::current_exception());
        }
    }

} // namespace cyclone::parser
